﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ChronoScript_Compiler.Language.Parser
{
    public partial class Parser
    {
        public LanguageDefinition.Expression ParseExpression(bool boolAND = false)
        {
            LanguageDefinition.Expression exp = new LanguageDefinition.Expression();
            while (!(PeekToken() is Tokens.EOL))
            {

                if (PeekToken() is Tokens.Equal)
                {
                    ReadToken();
                    LanguageDefinition.Equal equ = new LanguageDefinition.Equal();
                    equ.Op1 = exp;
                    exp = new LanguageDefinition.Expression();
                    equ.Op2 = ParseExpression(true);
                    exp.Items.Add(equ);
                }
                else if (PeekToken() is Tokens.BooleanAnd)
                {
                    ReadToken();
                    LanguageDefinition.And equ = new LanguageDefinition.And();
                    equ.Op1 = exp;
                    exp = new LanguageDefinition.Expression();
                    equ.Op2 = ParseExpression(true);
                    exp.Items.Add(equ);
                }
                else if (PeekToken() is Tokens.NotEqual)
                {
                    ReadToken();
                    LanguageDefinition.NotEqual equ = new LanguageDefinition.NotEqual();
                    equ.Op1 = exp;
                    exp = new LanguageDefinition.Expression();
                    equ.Op2 = ParseExpression(true);
                    exp.Items.Add(equ);
                }
                else if (PeekToken() is Tokens.GreaterThan)
                {
                    ReadToken();
                    LanguageDefinition.GreaterThan equ = new LanguageDefinition.GreaterThan();
                    equ.Op1 = exp;
                    exp = new LanguageDefinition.Expression();
                    equ.Op2 = ParseExpression(true);
                    exp.Items.Add(equ);
                }
                else if (PeekToken() is Tokens.LessThan)
                {
                    ReadToken();
                    LanguageDefinition.LessThan equ = new LanguageDefinition.LessThan();
                    equ.Op1 = exp;
                    exp = new LanguageDefinition.Expression();
                    equ.Op2 = ParseExpression(true);
                    exp.Items.Add(equ);
                }
                else
                {
                    LanguageDefinition.SyntaxNode Node = GetNode();
                    if (Node != null)
                    {
                        if (PeekToken() is Tokens.Add)
                        {
                            ReadToken();
                            LanguageDefinition.Plus pl = new LanguageDefinition.Plus();
                            pl.Op1 = Node;
                            pl.Op2 = GetNode();
                            exp.Items.Add(pl);
                        }
                        else if (PeekToken() is Tokens.Mul)
                        {
                            ReadToken();
                            LanguageDefinition.Multiply pl = new LanguageDefinition.Multiply();
                            pl.Op1 = Node;
                            pl.Op2 = GetNode();
                            exp.Items.Add(pl);
                        }
                        else if (PeekToken() is Tokens.Sub)
                        {
                            ReadToken();
                            LanguageDefinition.Subtract pl = new LanguageDefinition.Subtract();
                            pl.Op1 = Node;
                            pl.Op2 = GetNode();
                            exp.Items.Add(pl);
                        }
                        else if (PeekToken() is Tokens.RightBitshift)
                        {
                            ReadToken();
                            LanguageDefinition.RightBitshift bs = new LanguageDefinition.RightBitshift();
                            bs.Op1 = Node;
                            bs.Op2 = GetNode();
                            exp.Items.Add(bs);
                        }
                        else if (PeekToken() is Tokens.RightBitshift)
                        {
                            ReadToken();
                            LanguageDefinition.RightBitshift bs = new LanguageDefinition.RightBitshift();
                            bs.Op1 = Node;
                            bs.Op2 = GetNode();
                            exp.Items.Add(bs);
                        }
                        else if (PeekToken() is Tokens.LeftBitshift)
                        {
                            ReadToken();
                            LanguageDefinition.LeftBitshift bs = new LanguageDefinition.LeftBitshift();
                            bs.Op1 = Node;
                            bs.Op2 = GetNode();
                            exp.Items.Add(bs);
                        }
                        else
                        {
                            exp.Items.Add(Node);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }
            return exp;
        }
        public LanguageDefinition.SyntaxNode GetNode()
        {
            if (PeekToken() is Tokens.IntLiteral)
            {
                return (new LanguageDefinition.IntLiteral((uint)((Tokens.IntLiteral)ReadToken()).Value));
            }
            else if (PeekToken() is Tokens.StringLiteral)
            {
                return (new LanguageDefinition.StringLiteral(((Tokens.StringLiteral)ReadToken()).Value));
            }
            else if (PeekToken() is Tokens.Statement && PeekToken(1) is Tokens.openParenthesis)
            {
                return Call();
            }
            else if (PeekToken() is Tokens.openParenthesis)
            {
                ReadToken();
                LanguageDefinition.Expression exp = ParseExpression();
                if (!(ReadToken() is Tokens.closeParenthesis))
                    Console.WriteLine("Expected )");
                return exp;
            }
            else if (PeekToken() is Tokens.Statement)
            {
                return new LanguageDefinition.SymbolRef(ReadToken().ToString());
            }

            return null;
        }
    }
}
